package com.jwds.digital.bios.business.service.service.belt.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwds.digital.bios.business.core.exceptions.RecordNotFoundException;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.BeltRouteTaskDetailReqDTO;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.assembler.BeltRouteTaskDetailAssembler;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltRouteTaskDetail;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRouteTaskDetailMapper;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.BeltAnomalyInfoRespVO;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.BeltDayTargetHisRespVO;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.BeltRouteTaskDetailRespVO;
import com.jwds.digital.bios.business.service.service.belt.IBeltRouteTaskDetailService;
import com.jwds.tdc.framework.application.lib.page.PageRequest;
import com.jwds.tdc.framework.application.lib.page.PageResponse;
import com.jwds.tdc.framework.cache.service.CacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 路线作业实绩详情表实现类
 * @author 林柏云
 * @date 2024-11-28
 */
@Slf4j
@Service
public class BeltRouteTaskDetailServiceImpl extends ServiceImpl<BeltRouteTaskDetailMapper, BeltRouteTaskDetail> implements IBeltRouteTaskDetailService {

  @Autowired
  private BeltRouteTaskDetailMapper baseMapper;

  @Resource
  CacheService cacheService;
  // 皮带任务空载超时 缓存key
  private static final String CACHE_KEY_PELLET_NO_LOAD_TIMEOUT = "PELLET_NO_LOAD_TIMEOUT:";
  private static final Long CACHE_KEY_PELLET_NO_LOAD_TIMEOUT_TTL = 60*60*24L;

  @Override
  public BeltRouteTaskDetailRespVO queryById(Long id) {
    if(id == null) {
      return null;
    }
    BeltRouteTaskDetail entity = baseMapper.selectById(id);
    return BeltRouteTaskDetailAssembler.entity2dto(entity);
  }

  @Override
  public PageResponse<BeltRouteTaskDetailRespVO> page(PageRequest<BeltRouteTaskDetailReqDTO> request) {
    BeltRouteTaskDetailReqDTO condition = request.getQueryCondition();
    Page<BeltRouteTaskDetailRespVO> page = new Page<>(request.getPageIndex(), request.getPageSize());
    IPage<BeltRouteTaskDetailRespVO> pageData = baseMapper.pageQuery(page, condition);
    return new PageResponse<>((Page<?>)pageData, pageData.getRecords());
  }

  @Override
  public List<BeltRouteTaskDetailRespVO> list(BeltRouteTaskDetailReqDTO reqDto) {
    return baseMapper.queryList(reqDto);
  }

  @Override
  public void add(BeltRouteTaskDetailReqDTO reqDto) {
    BeltRouteTaskDetail entity = BeltRouteTaskDetailAssembler.dto2entity(reqDto);
    baseMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchAdd(List<BeltRouteTaskDetailReqDTO> dtoList) {
    dtoList.forEach(this::add);
  }

  @Override
  public void update(BeltRouteTaskDetailReqDTO reqDto) {
    BeltRouteTaskDetail oldEntity = baseMapper.selectById(reqDto.getId());
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    BeltRouteTaskDetail newEntity = BeltRouteTaskDetailAssembler.dto2entity(reqDto, oldEntity);
    baseMapper.updateById(newEntity);
  }

  @Override
  public void delete(Long id) {
    BeltRouteTaskDetail oldEntity = baseMapper.selectById(id);
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    baseMapper.deleteById(id);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchDelete(List<Long> ids) {
    for (Long id : ids) {
      delete(id);
    }
  }

  @Override
  public BeltRouteTaskDetailRespVO getHomeData(Date time) {
    BeltRouteTaskDetailRespVO beltRouteTaskDetailRespVO = new BeltRouteTaskDetailRespVO();

    List<BeltRouteTaskDetailRespVO> homeData = baseMapper.getHomeData(DateUtil.beginOfDay(time));

    // 获取线路历史信息
    BeltDayTargetHisRespVO beltRouteTargetHisRespVO = baseMapper.lineHistoryInformation(DateUtil.beginOfDay(time));

    if (CollectionUtils.isNotEmpty(homeData)) {
      // 运输总量
      BigDecimal totalTransport = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getTotalTransport)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 团球出料总量
      BigDecimal pelletDischarge = homeData.stream()
              .filter(home -> Objects.equals("团球", home.getTaskType()))
              .map(BeltRouteTaskDetailRespVO::getTotalTransport)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 烧结出料总量
      BigDecimal sinteringDischarge = homeData.stream()
              .filter(home -> Objects.equals("烧结", home.getTaskType()))
              .map(BeltRouteTaskDetailRespVO::getTotalTransport)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 作业时长
      BigDecimal runningTime = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getRunningTime)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 作业效率
      BigDecimal transportEfficiency = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getTransportEfficiency)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 总耗电量
      BigDecimal totalPowerConsumption = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getTotalPowerConsumption)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 空载运行时长占比
      BigDecimal unLoadRunningTime = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getUnLoadRunningTime)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 空载耗电量占比
      BigDecimal unLoadPowerConsumptionRate = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getUnLoadPowerConsumptionRate)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      // 吨料耗电量
      BigDecimal tonPowerConsumption = homeData.stream()
              .map(BeltRouteTaskDetailRespVO::getTonPowerConsumption)
              .filter(Objects::nonNull)
              .reduce(BigDecimal.ZERO, BigDecimal::add);

      if (Objects.nonNull(beltRouteTargetHisRespVO)) {

        // 作业效率上升或下降标识,百分比
        Integer workIdentification = transportEfficiency.compareTo(beltRouteTargetHisRespVO.getWorkEfficiency());
        BigDecimal workPercent = calculatePercentageChange(transportEfficiency, beltRouteTargetHisRespVO.getWorkEfficiency());
        beltRouteTaskDetailRespVO.setWorkIdentification(workIdentification);
        beltRouteTaskDetailRespVO.setWorkPercent(workPercent);

        // 总耗电量上升或下降标识,百分比
        Integer powerConsumption = totalPowerConsumption.compareTo(beltRouteTargetHisRespVO.getTotalPowerConsumption());
        BigDecimal powerConsumptionPercent = calculatePercentageChange(totalPowerConsumption, beltRouteTargetHisRespVO.getTotalPowerConsumption());
        beltRouteTaskDetailRespVO.setPowerConsumption(powerConsumption);
        beltRouteTaskDetailRespVO.setPowerConsumptionPercent(powerConsumptionPercent);

        // 空载运行时长上升或下降标识,百分比
        Integer unLoadRunning = unLoadRunningTime.compareTo(beltRouteTargetHisRespVO.getUnLoadRunningTime());
        BigDecimal unLoadRunningPercent = calculatePercentageChange(unLoadRunningTime, beltRouteTargetHisRespVO.getUnLoadRunningTime());
        beltRouteTaskDetailRespVO.setUnLoadRunning(unLoadRunning);
        beltRouteTaskDetailRespVO.setUnLoadRunningPercent(unLoadRunningPercent);

        // 空载耗电量上升或下降标识,百分比
        Integer unLoadPower = unLoadPowerConsumptionRate.compareTo(beltRouteTargetHisRespVO.getUnLoadPowerConsumptionRate());
        BigDecimal unLoadPowerPercent = calculatePercentageChange(unLoadPowerConsumptionRate, beltRouteTargetHisRespVO.getUnLoadPowerConsumptionRate());
        beltRouteTaskDetailRespVO.setUnLoadPower(unLoadPower);
        beltRouteTaskDetailRespVO.setUnLoadPowerPercent(unLoadPowerPercent);

        // 吨料耗电量上升或下降标识,百分比
        Integer tonPower = tonPowerConsumption.compareTo(beltRouteTargetHisRespVO.getTonPowerConsumption());
        BigDecimal tonPowerPercent = calculatePercentageChange(tonPowerConsumption, beltRouteTargetHisRespVO.getTonPowerConsumption());
        beltRouteTaskDetailRespVO.setTonPower(tonPower);
        beltRouteTaskDetailRespVO.setTonPowerPercent(tonPowerPercent);

      }

      beltRouteTaskDetailRespVO.setTotalTransport(totalTransport);
      beltRouteTaskDetailRespVO.setPelletDischarge(pelletDischarge);
      beltRouteTaskDetailRespVO.setSinteringDischarge(sinteringDischarge);
      beltRouteTaskDetailRespVO.setRunningTime(runningTime);
      beltRouteTaskDetailRespVO.setTransportEfficiency(transportEfficiency);
      beltRouteTaskDetailRespVO.setTotalPowerConsumption(totalPowerConsumption);
      beltRouteTaskDetailRespVO.setUnLoadRunningTime(unLoadRunningTime.divide(runningTime, 2, RoundingMode.HALF_UP));
      beltRouteTaskDetailRespVO.setUnLoadPowerConsumption(unLoadPowerConsumptionRate);
      beltRouteTaskDetailRespVO.setTonPowerConsumption(tonPowerConsumption);
      beltRouteTaskDetailRespVO.setStartAndStopCount(homeData.size());

    }

    return beltRouteTaskDetailRespVO;
  }

  @Override
  public List<BeltAnomalyInfoRespVO> alarmMessage() {
    return baseMapper.alarmMessage();
  }


  /**
   * 检查任务是否存在空载超时的情况
   *
   * @param taskId 任务ID
   * @return 如果任务超时返回 true，否则返回 false
   */
  @Override
  public Boolean checkNoLoadTimeOut(Long taskId) {
    String cacheKey = CACHE_KEY_PELLET_NO_LOAD_TIMEOUT + taskId;

    // 如果缓存中存在该任务的超时记录，直接返回 false
    if (cacheService.getString(cacheKey) != null) {
      return false;
    }

    // 查询该任务的最近两条任务记录，并按结束时间降序排列
    List<BeltRouteTaskDetail> list = this.list(
            new LambdaQueryWrapper<BeltRouteTaskDetail>()
                    .eq(BeltRouteTaskDetail::getTaskId, taskId)
                    .orderByDesc(BeltRouteTaskDetail::getEndTime)
                    .last("limit 2")
    );

    // 如果记录不足两条，则无法判断超时，直接返回 false
    if (list == null || list.size() < 2) {
      return false;
    }

    // 计算前两条记录的空载运行时间总和
    BigDecimal totalTime = list.stream()
            .limit(2)
            .map(BeltRouteTaskDetail::getUnLoadRunningTime)
            .reduce(BigDecimal.ZERO, BigDecimal::add);

    // 比较总时间是否大于 10，如果是则标记为超时
    boolean isTimeout = totalTime.compareTo(new BigDecimal("10")) > 0;

    // 如果超时，将结果存入缓存
    if (isTimeout) {
      cacheService.setStringExpired(cacheKey, Boolean.TRUE.toString(), CACHE_KEY_PELLET_NO_LOAD_TIMEOUT_TTL);
    }

    // 返回超时状态
    return isTimeout;
  }



  /**
   * 计算变化百分比
   * @param newValue 新值
   * @param oldValue 旧值
   * @return 变化百分比
   */
  private static BigDecimal calculatePercentageChange(BigDecimal newValue, BigDecimal oldValue) {

    if (oldValue.compareTo(BigDecimal.ZERO) == 0) {
//      throw new ArithmeticException("Cannot calculate percentage change when the old value is zero.");
      return BigDecimal.ZERO;
    }

    // 避免除以零的情况
    BigDecimal change = newValue.subtract(oldValue);
    BigDecimal percentageChange = change.divide(oldValue, 2, RoundingMode.HALF_UP);
    return percentageChange;
  }

}
